import { ConstraintType, EventsRes, SceneGraph } from '@amcax/base';
import { ctx2 } from '@app-cad/module';
import {
  calculatePoint,
  distanceToLine,
  getAngle,
  isEquals,
} from '@app-cad/common/utils';
import { wsApi } from '@app-cad/server';
import { Vector2, Vector2tuple, Vector3 } from 'three-legacy';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import CmdBase, { ConstraintsType, PickType, SnapType } from '../../CmdBase';
import { dimension } from '../dimension/Dimension';
import { MousePoint, MouseState, State } from './types';
import { AnnotationType } from '../dimension/types';
type Point = Vector2tuple | string;
type Param = {
  center: Point;
  point1: Point;
  point2: Point;
  curveStyle?: number;
  constraints?: Array<ConstraintsType<ConstraintType>>;
  annotations?: Array<ConstraintsType<AnnotationType>>;
};
export default class CmdInteractor extends CmdBase {
  startPoint: Vector3; // 圆弧的起点
  centerPoint: Vector3; // 圆心点
  endPoint: Vector3; // 圆弧的终点
  startAngle: number = 0; // 起始角度
  endAngle: number = 0; // 结束角度
  radius: number = 0; // 圆半径
  clockWise: boolean | undefined = undefined; // 逆时针与否
  mousePoint: MousePoint = { x: 0, y: 0 };
  currentStatus: MouseState = State.NONE; // 记录当前状态
  lastMousePos;
  speed: number = 0;
  private centerSnapInfo: SnapType;
  private firstSapnInfo: SnapType;
  private endSnapInfo: SnapType;

  constructor() {
    super();
    this.registerEvents();
  }

  reset = () => {
    this.currentStatus = State.NONE;
    this.startPoint = null;
    this.centerPoint = null;
    this.endPoint = null;
    this.startAngle = 0;
    this.endAngle = 0;
    this.radius = 0;
    this.clockWise = undefined;
    this.mousePoint = { x: 0, y: 0 };
    this.centerSnapInfo = null;
    this.firstSapnInfo = null;
    this.endSnapInfo = null;
    this.removeTempPoint();
  };
  registerEvents = () => {
    dimension().reset();
    sketchEventCenter()
      .setState('arc')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseUp)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
  };
  unregisterEvents = () => {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseUp)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
  };
  releaseObjects = () => {
    dimension()?.destroy();
    this.clearLine();
    this.assisGroup.clear();
    SceneGraph.emptyGroup(this.assisGroup);
    ctx2.viewer.requestRender();
  };
  enterKeyDown = () => {
    if (this.currentStatus === State.DRAW_CIRCLE) {
      dimension().determineDim();
      this.setLineLength();
      this.preview();
    }
  };
  setLineLength = () => {
    if (dimension().dimType === 'create') {
      const vec = new Vector3()
        .subVectors(this.startPoint, this.centerPoint)
        .normalize();
      this.startPoint = calculatePoint(
        vec,
        dimension().getDimInfo().value,
        this.centerPoint,
      );
    }
    this.radius = this.startPoint.distanceTo(this.centerPoint);
    // 添加辅助点，用来做定点捕捉
    this.createAssistPoint(this.startPoint, true);
  };
  onMouseMove = (e: EventsRes) => {
    const event = e.event as PointerEvent;
    const currentMousePos = { x: event.clientX, y: event.clientY };
    if (this.lastMousePos) {
      const diffX = currentMousePos.x - this.lastMousePos.x;
      const diffY = currentMousePos.y - this.lastMousePos.y;
      this.speed = Math.sqrt(diffX * diffX + diffY * diffY) / 16.67; // 假设16.67毫秒为帧率，根据实际情况可能需要调整
    }
    this.lastMousePos = currentMousePos;
    // 在面上画弧形
    this.setMouseWV(e, true);
    if (this.currentStatus === State.DRAW_CIRCLE) {
      this.startPoint = this.mouseWV.clone();
      this.setLineLength();
      this.preview();
    } else if (this.currentStatus === State.DRAW_ARC) {
      this.endPoint = this.mouseWV.clone();
      this.preview();
    }
  };
  onMouseUp = (e: EventsRes) => {
    if (e.button.onLeft) {
      if (this.currentStatus === State.NONE) {
        if (this.pickType !== PickType.Null) {
          this.centerSnapInfo = {
            pickType: this.pickType,
            curveId: this.pickSnapInfo?.id,
            point: this.mouseWV.clone(),
          };
        }
        // 鼠标左键，开始绘制圆心
        this.centerPoint = this.mouseWV.clone();
        this.createAssistPoint(this.centerPoint, null, null, true);
        this.currentStatus = State.DRAW_CIRCLE;
      } else if (this.currentStatus === State.DRAW_CIRCLE) {
        this.currentStatus = State.DRAW_ARC;
        if (this.pickType !== PickType.Null) {
          this.firstSapnInfo = {
            pickType: this.pickType,
            curveId: this.pickSnapInfo?.id,
            point: this.mouseWV.clone(),
          };
        }
        if (!dimension().getDimInfo()) {
          dimension().destroy();
        }
      } else if (this.currentStatus === State.DRAW_ARC) {
        if (this.pickType !== PickType.Null) {
          this.endSnapInfo = {
            pickType: this.pickType,
            curveId: this.pickSnapInfo?.id,
            point: this.mouseWV.clone(),
          };
        }
        this.currentStatus = State.FINISH;
        // 鼠标左键，完成
        this.finishDraw();
        // this.destroy();
      }
    } else if (e.button.onRight && !this.closeRightClick) {
      this.currentStatus = State.NONE;
      // 鼠标右键，放弃
      // this.destroy();
      this.abandon();
    }
  };

  abandon(): void {
    this.reset();
    this.releaseObjects();
    dimension().destroy();
  }

  calcPointWithDistance = (start: Vector3, end: Vector3, distance: number) => {
    const p = end.clone().sub(start).setLength(distance).add(start);
    return p;
  };

  async finishDraw() {
    if (this.radius != 0) {
      const param = this.getParams(this.clockWise);
      const res = await wsApi.createSketchArcOfCircle(this.sketchId, param);
      await this.render(
        { added: res.added },
        param.annotations.some((item) => item != null),
      );
      this.abandon();
    }
  }
  getParams(flag: boolean) {
    const param: Param = {
      center: [this.centerPoint.x, this.centerPoint.y],
      point1: flag
        ? [this.endPoint.x, this.endPoint.y]
        : [this.startPoint.x, this.startPoint.y],
      point2: flag
        ? [this.startPoint.x, this.startPoint.y]
        : [this.endPoint.x, this.endPoint.y],
      curveStyle: this.lineType,
      constraints: this.addConstraint(),
      annotations: null,
    };
    if (this.centerSnapInfo?.curveId) {
      const { curveId, pickType, point } = this.centerSnapInfo;
      if (isEquals(point, this.centerPoint) && pickType === PickType.Point) {
        param.center = curveId;
      }
    }
    if (this.firstSapnInfo?.curveId) {
      const { curveId, pickType, point } = this.firstSapnInfo;
      if (isEquals(point, this.startPoint) && pickType === PickType.Point) {
        param[flag ? 'point2' : 'point1'] = curveId;
      }
    }
    if (this.endSnapInfo?.curveId) {
      const { curveId, pickType, point } = this.endSnapInfo;
      if (isEquals(point, this.endPoint) && pickType === PickType.Point) {
        param[flag ? 'point1' : 'point2'] = curveId;
      }
    }
    param.annotations = [dimension().addDimension()];
    return param;
  }

  addConstraint() {
    const constraints = [];
    if (this.centerSnapInfo?.curveId) {
      constraints.push(
        this.getConstraint(this.centerSnapInfo, this.centerPoint, false),
      );
    }
    if (this.firstSapnInfo?.curveId) {
      constraints.push(
        this.getConstraint(this.firstSapnInfo, this.startPoint, false),
      );
    }
    if (this.endSnapInfo?.curveId) {
      constraints.push(
        this.getConstraint(this.endSnapInfo, this.endPoint, false),
      );
    }
    return constraints.filter((item) => item != null);
  }
  // 计算点到直线的距离是否超过圆弧半径
  isDistanceExceedRadius(vertices): boolean {
    if (vertices.length === 2) {
      const p1 = new Vector3(vertices[0][0], vertices[0][1], 0);
      const p2 = new Vector3(vertices[1][0], vertices[1][1], 0);
      const vec = p2.clone().sub(p1).normalize();
      return (
        distanceToLine(this.centerPoint, {
          start: p1,
          vec,
          normal: new Vector3(vec.y, -vec.x, 0),
        }) <= this.radius
      );
    }
    return null;
  }

  getArcParams(clockWise: boolean = true) {
    let point1 = this.startPoint.clone();
    if (!this.startAngle) {
      this.startAngle = getAngle(point1, this.centerPoint);
    }
    this.endAngle = getAngle(this.endPoint, this.centerPoint);
    point1 = this.calcPointWithDistance(this.centerPoint, point1, this.radius);
    this.endPoint = this.calcPointWithDistance(
      this.centerPoint,
      this.endPoint,
      this.radius,
    );
    if (Math.abs(this.startAngle - this.endAngle) < 0.001) {
      return [];
    }
    return this.getArcVertexs({
      x: this.centerPoint.x,
      y: this.centerPoint.y,
      radius: this.radius,
      startAngle: this.startAngle,
      endAngle: this.endAngle,
      clockWise,
    });
  }

  preview() {
    if (this.currentStatus === State.DRAW_CIRCLE) {
      dimension().dimLine([this.startPoint, this.centerPoint]); // 画半径
      // 画辅助图形
      this.drawAssist(this.centerPoint, this.startPoint);
    } else if (this.currentStatus === State.DRAW_ARC) {
      // 绘制圆弧
      if (this.startPoint) {
        const v1 = this.startPoint.clone().sub(this.centerPoint);
        const v2 = this.endPoint.clone().sub(this.centerPoint);
        const diff = Math.min(this.speed / 4, Math.PI / 8);
        if (v1.angleTo(v2) < diff) {
          // 终止点靠近起始点时，重新计算顺逆时针方向
          this.clockWise = undefined;
        }
        if (this.clockWise == undefined) {
          this.clockWise = this.isClockwise([
            new Vector2(this.startPoint.x, this.startPoint.y),
            new Vector2(this.endPoint.x, this.endPoint.y),
            new Vector2(this.centerPoint.x, this.centerPoint.y),
          ]);
        }
        const params = this.getArcParams(this.clockWise);
        this.createUpdateLine(params);
        this.drawAssist(this.centerPoint, this.endPoint);
      }
    }
    ctx2.viewer.requestRender();
  }

  drawAssist(p1: Vector3, p2: Vector3) {
    this.createUpdateLine([p1, p2], 'rline', 1);
  }

  // 计算是否是顺逆时针
  isClockwise(points: Array<Vector2>) {
    const p12 = points[1].clone().sub(points[0]);
    const p23 = points[2].clone().sub(points[1]);
    const k = p12.cross(p23);
    if (k > 0) {
      // 顺时针
      return false;
    } else if (k < 0) {
      // 逆时针
      return true;
    }
    return true;
  }
}
